package com.xbongbong.pro.statistic.service.result;

import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.JsonHelperUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.constant.CommonConstant;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.domain.entity.ChartEntity;
import com.xbongbong.pro.service.toolbox.statistic.util.ChartResultUtil;
import com.xbongbong.pro.statistic.constant.ChartI18Constant;
import com.xbongbong.pro.statistic.enums.NumFormatEnum;
import com.xbongbong.pro.statistic.enums.PanoramaEnum;
import com.xbongbong.pro.statistic.enums.SystemCodeEnum;
import com.xbongbong.pro.statistic.enums.ValueTypeEnum;
import com.xbongbong.pro.statistic.pojo.FiscalYearTimePojo;
import com.xbongbong.pro.statistic.pojo.TimePojo;
import com.xbongbong.pro.statistic.pojo.vo.ContractInfoVO;
import com.xbongbong.pro.statistic.pojo.vo.ContractPerformanceInfoVO;
import com.xbongbong.pro.statistic.result.pojo.ChartResultBasePojo;
import com.xbongbong.pro.statistic.result.pojo.ChartResultPkPojo;
import com.xbongbong.pro.statistic.result.pojo.ChartResultPojo;
import com.xbongbong.pro.statistic.result.pojo.ElasticAggsPojo;
import com.xbongbong.pro.statistic.result.pojo.MomYoyTimeListPojo;
import com.xbongbong.pro.statistic.result.pojo.PanoramaPojo;
import com.xbongbong.pro.statistic.result.pojo.TopResultPojo;
import com.xbongbong.pro.statistic.result.pojo.dto.StatisticResultDTO;
import com.xbongbong.pro.statistic.result.pojo.dto.StatisticResultInfoDTO;
import com.xbongbong.pro.statistic.result.pojo.vo.ChartResultDetailVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ChartResultPkDetailVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultCountListVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultDataTableVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultDoubleListVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultTableVO;
import com.xbongbong.pro.statistic.through.pojo.dto.ThroughDTO;
import com.xbongbong.saas.domain.entity.ContractPerformanceEntity;
import com.xbongbong.saas.enums.CompanyConfigEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.model.CompanyConfigModel;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * 合同相关统计
 *
 * @author 徐俊杰
 * @version v1.0
 * @date 2019/2/27 9:54
 * @since v1.0
 */
@Service
public class CrmContractResult extends ChartResultParentService implements ChartResultSystem, ChartResultPk, PanoramaResult {
    private static final Logger LOG = LoggerFactory.getLogger(CrmContractResult.class);
    @Resource
    private CompanyConfigModel companyConfigModel;
    @Resource
    private CrmPaymentResult crmPaymentResult;

    @Override
    public Object getTarget(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        SystemCodeEnum systemCodeEnum = chartResultPojo.getSystemCodeEnum();
        switch (systemCodeEnum) {
            //合同数量相关
            case CONTRACT_COUNT_HOME:
                return contractCount(chartResultPojo, chartResultDetailVO);
            case CONTRACT_COUNT_HOME_MOM:
                //合同数量、环比
                return contractMomYoy(true, true, null, chartResultPojo, chartResultDetailVO);
            case CONTRACT_COUNT_HOME_YOY:
                //合同数量、同比
                return contractMomYoy(true, false, null, chartResultPojo, chartResultDetailVO);
            case CONTRACT_COUNT_CHART:
                return contractCountChart(chartResultPojo, chartResultDetailVO);
            //合同金额相关
            case CONTRACT_AMOUNT_HOME:
                return contractAmount(chartResultPojo, chartResultDetailVO);
            case CONTRACT_AMOUNT_HOME_MOM:
                //合同金额、环比
                return contractMomYoy(false, true, ContractEnum.AMOUNT, chartResultPojo, chartResultDetailVO);
            case CONTRACT_AMOUNT_HOME_YOY:
                //合同金额、同比
                return contractMomYoy(false, false, ContractEnum.AMOUNT, chartResultPojo, chartResultDetailVO);
            case CONTRACT_AMOUNT_CHART:
                return contractAmountChart(chartResultPojo, chartResultDetailVO);
            case CONTRACT_TABLE_CHART:
                return contractTable(chartResultPojo, chartResultDetailVO);
            //红冲合同金额相关
            case RED_CONTRACT_HOME:
                return redContractHome(chartResultPojo, chartResultDetailVO);
            case RED_CONTRACT_CHART:
                return redContractChart(chartResultPojo, chartResultDetailVO);
            case CONTRACT_CUSTOMER_CHART_TOP:
                return contractCustomerChartTop(chartResultPojo, chartResultDetailVO);
            //合同毛利、现金毛利
            case CONTRACT_PROFIT_CHART:
                return contractProfitChart(chartResultPojo, chartResultDetailVO);
            case CONTRACT_PROFIT_CHART_CASH:
                return contractProfitChartCash(chartResultPojo, chartResultDetailVO);
            default:
                break;
        }
        return null;
    }

    @Override
    public Object getValueTarget(ChartResultPojo chartResultPojo) throws XbbException {
        SystemCodeEnum systemCodeEnum = chartResultPojo.getSystemCodeEnum();
        switch (systemCodeEnum) {
            //合同数量相关
            case CONTRACT_COUNT_BOARD:
                return contractCountBoard(chartResultPojo);
            //合同金额相关
            case CONTRACT_AMOUNT_BOARD:
                return contractAmountBoard(chartResultPojo);
            case CONTRACT_PROFIT_BOARD:
                return contractProfitBoard(chartResultPojo);
            default:
                break;
        }
        return null;
    }

    @Override
    public Object getPkTarget(UserEntity userEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO) throws XbbException {
        SystemCodeEnum systemCodeEnum = chartResultPkPojo.getSystemCodeEnum();
        switch (systemCodeEnum) {
            //pk、完成情况（员工排行）
            case PK_CONTRACT_COUNT:
            case PERFORMANCE_CONTRACT_COUNT:
                return pkContractCount(userEntity, chartResultPkPojo, chartResultPkDetailVO);
            case PK_CONTRACT_AMOUNT:
            case PERFORMANCE_CONTRACT_AMOUNT:
                return pkContractAmount(userEntity, chartResultPkPojo, chartResultPkDetailVO);
            case PK_CONTRACT_PROFIT:
            case PERFORMANCE_CONTRACT_PROFIT:
                return pkContractProfit(userEntity, chartResultPkPojo, chartResultPkDetailVO);
            default:
                break;
        }
        return null;
    }

    /**
     * 系统pk范围规则指标公共接口
     *
     * @param userEntity            登录员工
     * @param chartEntity
     * @param chartResultPkPojo     pk参数
     * @param chartResultPkDetailVO 塞入pk结果
     * @return java.lang.Object
     * @throws XbbException
     * @author zcp
     * @date 2019/3/18 15:34
     * @version v1.0
     * @since v1.0
     */
    @Override
    public Object getPkRuleTarget(UserEntity userEntity, ChartEntity chartEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO) throws XbbException {
        SystemCodeEnum systemCodeEnum = chartResultPkPojo.getSystemCodeEnum();
        switch (systemCodeEnum) {
            //pk、完成情况（员工排行）
            case PK_CONTRACT_COUNT:
            case PERFORMANCE_CONTRACT_COUNT:
                return pkRuleContractCount(userEntity, chartEntity, chartResultPkPojo, chartResultPkDetailVO);
            case PK_CONTRACT_AMOUNT:
            case PERFORMANCE_CONTRACT_AMOUNT:
                return pkRuleContractAmount(userEntity, chartEntity, chartResultPkPojo, chartResultPkDetailVO);
            case PK_CONTRACT_PROFIT:
            case PERFORMANCE_CONTRACT_PROFIT:
                return pkRuleContractProfit(userEntity, chartEntity, chartResultPkPojo, chartResultPkDetailVO);
            default:
                break;
        }
        return null;
    }

    @Override
    public Object customer(PanoramaPojo panoramaPojo) throws XbbException {
        PanoramaEnum panoramaEnum = panoramaPojo.getPanoramaEnum();
        switch (panoramaEnum) {
            case CUSTOMER_CONTRACT_COUNT:
                return panoramaCustomerContract(true, panoramaPojo);
            case CUSTOMER_CONTRACT_AMOUNT:
                return panoramaCustomerContract(false, panoramaPojo);
            case CUSTOMER_CONTRACT_CYCLE:
                return panoramaCustomerContractCycle(panoramaPojo);
            case CUSTOMER_CONTRACT_TIME_LAST:
                return panoramaCustomerContractTimeLast(panoramaPojo);
            default:
                break;
        }
        return null;
    }
    
    /**
     * 客户合同数/金额
     *
     * @param countFlag true处理新增数量，false处理新增金额
     * @param panoramaPojo 全景参数pojo
     * @return java.lang.String
     * @author zcp
     * @date 2019/6/3 21:33
     * @since v1.0
     * @version v1.0
     */
    public String panoramaCustomerContract(boolean countFlag, PanoramaPojo panoramaPojo) throws XbbException {
        //ES获取客户的合同
        //不排除特定合同状态，限制负责人，且不限制时间
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.panoramaQuery4Contract(panoramaPojo);
        if (countFlag) {
            ElasticAggsPojo elasticAggsPojo = esHelper.elasticAggs(IndexTypeEnum.IDX_SAAS_CONTRACT, boolQueryBuilder, null);
            return elasticAggsPojo.getTotal();
        } else {
            /*--------得到合同金额--------*/
            String sumField = ContractEnum.getEsAttr4Keyword(ContractEnum.AMOUNT);
            double value = systemChartHelp.getDouble4Total(IndexTypeEnum.IDX_SAAS_CONTRACT, boolQueryBuilder, sumField);
            return ChartResultUtil.formatValue2Double(false, ValueTypeEnum.VALUE_MONEY, false, value, NumFormatEnum.DEFAULT, false);
        }
    }

    /**
     * 客户全景图---复购周期
     * @param panoramaPojo
     * @return java.lang.String
     * @throws XbbException
     * @author zcp
     * @date 2019/6/4 15:39
     * @since v1.0
     * @version v1.0
     */
    public String panoramaCustomerContractCycle(PanoramaPojo panoramaPojo) throws XbbException {
        //-------------（1）ES获取客户的合同总数
        //不排除特定合同状态，限制负责人，且不限制时间
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.panoramaQuery4Contract(panoramaPojo);
        ElasticAggsPojo elasticAggsPojo = esHelper.elasticAggs(IndexTypeEnum.IDX_SAAS_CONTRACT, boolQueryBuilder, null);
        String total = elasticAggsPojo.getTotal();
        int size = StringUtil.toInt(total, 0);

        //复购周期
        String cycleDay = "-";
        //-------------（2）当合同总数size<=1，则无需计算复购周期，否则才计算复购周期（即size>1时才计算）
        /**
         购买间隔的平均值。（单位：天）举例：订单2与订单1间隔10天，订单3与订单2间隔9天。则平均复购周期=(10+9)/2=9.5天，按照该公式，可推出，总天数用第一个减去最后一个的签订时间即可（按照签订时间倒序处理过）
         （1）关于间隔天数问题，比如6月3号签约1个合同，6月4号也签约一个合同，则算间隔1天
         （2）只有1条合同，复购周期为0
         （3）没有合同，则复购周期为“-”
         */
        if (size > 1) {
            //-------------（3）此时大于等于2条合同，根据上述描述，复购周期用（第最后一个签订的时间 - 第一个签订时间）/size 即得到复购周期
            //最后一个签订的：签订时间倒序
            List<PaasFormDataEntityExt> listEnd = formHelp.panoramaCustomer4SortedContractListByPage(SortOrder.DESC, boolQueryBuilder);
            //最早签订的：签订时间升序
            List<PaasFormDataEntityExt> listFirst = formHelp.panoramaCustomer4SortedContractListByPage(SortOrder.ASC, boolQueryBuilder);

            ContractEnum enumTime = ContractEnum.SIGN_TIME;
            //最后一个签订的
            JSONObject dataEnd = JsonHelperUtil.getJSONObject(listEnd.get(0).getData());
            //最早签订的
            JSONObject dataFirst = JsonHelperUtil.getJSONObject(listFirst.get(0).getData());
            Long signTimeEnd = dataEnd.getLongValue(enumTime.getAttr());
            Long signTimeFirst = dataFirst.getLongValue(enumTime.getAttr());
            //第一个减去最后一个
            Integer day = DateUtil.lastConnect(signTimeFirst.intValue(), signTimeEnd.intValue());
            //平均复购天数，无需保留小数（此处size大于1，因此size-1肯定不为0）
            int rateDay = (int) Arith.div(day, size - 1d);
            cycleDay = String.valueOf(rateDay);
        } else {
            //就1条合同，复购周期为0
            cycleDay = "0";
        }
        return cycleDay;
    }
    /**
     * 客户全景图--距离上次成交时长
     * @param panoramaPojo
     * @return java.lang.String
     * @throws XbbException
     * @author zcp
     * @date 2019/6/4 14:45
     * @since v1.0
     * @version v1.0
     */
    public String panoramaCustomerContractTimeLast(PanoramaPojo panoramaPojo) throws XbbException {
        List<PaasFormDataEntityExt> list = formHelp.panoramaCustomer4SortedContractListByPage(panoramaPojo, SortOrder.DESC);
        ContractEnum enumTime = ContractEnum.SIGN_TIME;
        Long signTimeLong = null;
        for (PaasFormDataEntityExt entityExt : list) {
            JSONObject data = JsonHelperUtil.getJSONObject(entityExt.getData());
            signTimeLong = data.getLong(enumTime.getAttr());
            if (signTimeLong != null) {
                break;
            }
        }
        String timeLast = ChartResultUtil.getTimeLast(signTimeLong);
        return timeLast;
    }

    /**
     * 合同数量
     *
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return java.lang.Object
     * @throws XbbException
     * @author 徐俊杰
     * @date 2019/2/28 13:37
     * @since v1.0
     */
    public Object contractCount(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        ElasticAggsPojo elasticAggsPojo = contractCount2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.ARRAY_TYPE);
        ThroughDTO throughDTO = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        //是否画入表格内 0否1是
        Integer tableFlag = 1;
        String legend = null;
        String unit = null;
        Boolean totalFlag = false;
        String valueTitle = null;
        return systemChartHelp.packageResult4One(elasticAggsPojo, chartResultPojo, chartResultDetailVO, throughDTO, tableFlag, legend, unit, totalFlag, valueTitle);
    }

    /**
     * 图表中心合同数量（包含上月，去年当月，环比增长，同比增长）
     *
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return java.lang.Object
     * @throws XbbException
     * @author 徐俊杰
     * @date 2019/2/28 13:39
     * @since v1.0
     */
    public Object contractCountChart(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        List<String> legendList = Arrays.asList(I18nMessageUtil.getMessage(ChartI18Constant.CONTRACT_NUMBER_ANALYSIS).split(","));
        String unit = systemChartHelp.getUnit(I18nMessageUtil.getMessage(CommonConstant.EACH));
        String unit1 = systemChartHelp.getUnit("%");
        List<String> unitList = Arrays.asList(unit, unit, unit, unit1, unit1);
        StatisticResultDTO statisticResultDto = getStatisticResultDto4MomYoy(true, chartResultPojo, legendList, unitList, null);

        //右侧展示总数
        statisticResultDto.setTotalFlag(true);
        statisticResultDto.setValueTitle(I18nMessageUtil.getMessage(ChartI18Constant.CONTRACT_NUMBER));
        chartResultDetailVO = systemChartHelp.packageResult(statisticResultDto, chartResultPojo, chartResultDetailVO);
        return chartResultDetailVO;
    }

    /**
     * 签约合同金额
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return java.lang.Object
     * @throws XbbException
     * @author zcp
     * @date 2019/2/28 14:08
     * @since v1.0
     * @version v1.0
     */
    public Object contractAmount(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        //不限制红冲
        Integer isRed = null;
        ElasticAggsPojo elasticAggsPojo = contractAmount2ElasticAggsPojo(isRed, chartResultPojo, ValueTypeEnum.ARRAY_TYPE, ContractEnum.AMOUNT);
        ThroughDTO throughDTO = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        //是否画入表格内 0否1是
        Integer tableFlag = 1;
        String legend = SystemCodeEnum.CONTRACT_AMOUNT_HOME.getName();
        String unit = NumFormatEnum.getByCode(chartResultPojo.getNumFormat()).getUnit();
        Boolean totalFlag = true;
        String valueTitle = SystemCodeEnum.CONTRACT_AMOUNT_HOME.getName();
        return systemChartHelp.packageResult4One(elasticAggsPojo, chartResultPojo, chartResultDetailVO, throughDTO, tableFlag, legend, unit, totalFlag, valueTitle);
    }

    /**
     * 合同订单数（简报看板）
     *
     * @param chartResultPojo
     * @return java.lang.String
     * @throws XbbException 查询订单数时抛出异常
     * @author 徐俊杰
     * @date 2019/3/12 19:17
     * @since v1.0
     */
    public String contractCountBoard(ChartResultPojo chartResultPojo) throws XbbException {
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.contractQuery4SignNoRed(chartResultPojo);
        // chartRuleQueryHelp.formOpenBase(boolQueryBuilder, chartResultPojo, XbbRefTypeEnum.CONTRACT);
        ElasticAggsPojo elasticAggsPojo = esHelper.elasticAggs(IndexTypeEnum.IDX_SAAS_CONTRACT, boolQueryBuilder, null);
        return elasticAggsPojo.getTotal();
    }
    /**
     * 合同金额分析
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return java.lang.Object
     * @throws XbbException
     * @author zcp
     * @date 2019/2/28 14:48
     * @since v1.0
     * @version v1.0
     */
    public Object contractAmountChart(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        List<String> legendList = Arrays.asList(I18nMessageUtil.getMessage(ChartI18Constant.CONTRACT_AMOUNT_ANALYSIS).split(","));
        String unit = systemChartHelp.getUnit(I18nMessageUtil.getMessage(CommonConstant.YUAN));
        String unit1 = systemChartHelp.getUnit("%");
        List<String> unitList = Arrays.asList(unit, unit, unit, unit1, unit1);
        StatisticResultDTO statisticResultDto = getStatisticResultDto4MomYoy(false, chartResultPojo, legendList, unitList, ContractEnum.AMOUNT);

        //右侧展示总数
        statisticResultDto.setTotalFlag(true);
        statisticResultDto.setValueTitle(I18nMessageUtil.getMessage(ChartI18Constant.CONTRACT_TOTAL_MONEY));
        chartResultDetailVO = systemChartHelp.packageResult(statisticResultDto, chartResultPojo, chartResultDetailVO);
        return chartResultDetailVO;
    }

    /**
     * 合同订单金额（简报看板）
     *
     * @param chartResultPojo
     * @return java.lang.String
     * @throws XbbException 查询订单金额时抛出异常
     * @author 徐俊杰
     * @date 2019/3/12 19:23
     * @since v1.0
     */
    public String contractAmountBoard(ChartResultPojo chartResultPojo) throws XbbException {
        //不限制红冲合同
        Integer isRed = null;
        //ES获取合同金额
        ElasticAggsPojo elasticAggsPojo = contractAmount2ElasticAggsPojo(isRed, chartResultPojo, ValueTypeEnum.VALUE_TYPE, ContractEnum.AMOUNT);
        return ChartResultUtil.formatValue2String(false, ValueTypeEnum.VALUE_MONEY, chartResultPojo.isThousandSwitch(), elasticAggsPojo.getTotal(), NumFormatEnum.getByCode(chartResultPojo.getNumFormat()), chartResultPojo.getNumFormatFlag());
    }

    /**
     * 合同汇总报表
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return java.lang.Object
     * @throws XbbException
     * @author zcp
     * @date 2019/2/28 21:16
     * @since v1.0
     * @version v1.0
     */
    public Object contractTable(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        ResultCountListVO contractCountListVO = contractCount2ResultCountListVO(chartResultPojo, ValueTypeEnum.ARRAY_TYPE);
        ResultDoubleListVO contractAmountListVO = contractAmount2ResultDoubleListVO(chartResultPojo, ValueTypeEnum.ARRAY_TYPE);
        ResultDoubleListVO paymentEdListVO = crmPaymentResult.paymentEd2ResultDoubleListVO(chartResultPojo, ValueTypeEnum.ARRAY_TYPE);
        double unAmount = crmPaymentResult.paymentUn(chartResultPojo);
        String unit = chartResultPojo.getUnit();
        Integer numFormat = chartResultPojo.getNumFormat();
        NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(numFormat);
        //未收款金额在上面的方法中并不会进行格式化，这里还是按照用户选择的NumFormatEnum进行格式化
        String formatUnAmount = ChartResultUtil.formatValAndUnit2Thousands(BigDecimal.valueOf(unAmount), numFormatEnum, unit);
        //合同金额、回款金额在上面的方法内可能会进行数值格式化，为了避免重复格式化这里手动将NumFormatEnum置为默认格式
        if(Objects.nonNull(chartResultPojo.getNumFormatFlag()) && chartResultPojo.getNumFormatFlag()){
            numFormatEnum = NumFormatEnum.DEFAULT;
        }
        //-----设置返回的resultTableVO的各个数据
        ResultTableVO resultTableVO = new ResultTableVO();
        //设置table名称
        resultTableVO.setTableName(chartResultPojo.getSystemCodeEnum().getName());
        //（1）设置headMemo
        String headMemo =String.format(I18nMessageUtil.getMessage(ChartI18Constant.CONTRACT_SUMMARY_MESSAGE),contractCountListVO.getTotal(), ChartResultUtil.formatValAndUnit2Thousands(BigDecimal.valueOf(contractAmountListVO.getTotal()), numFormatEnum, unit), ChartResultUtil.formatValAndUnit2Thousands(BigDecimal.valueOf(paymentEdListVO.getTotal()), numFormatEnum, unit), formatUnAmount);
        resultTableVO.setHeadMemo(headMemo);

        //（2）设置title
        List<String> title = Arrays.asList(String.format(I18nMessageUtil.getMessage(ChartI18Constant.CONTRACT_SUMMARY_TITLE), unit, unit).split(","));
        resultTableVO.setTitle(systemChartHelp.titleNumRight(title));
        //（3）设置data
        List<List<ResultDataTableVO>> resultDataTableVOList = new ArrayList<>();
        //每行的数据
        List<String> dateTitleList = new ArrayList<>(chartResultPojo.getDateTitleList());
        List<Integer> contractCountList = contractCountListVO.getResultList();
        List<Double> contractAmountList = contractAmountListVO.getResultList();
        List<Double> paymentEdList = paymentEdListVO.getResultList();
        //处理穿透
        List<Integer> startTimeList = chartResultPojo.getStartTimeList();
        List<Integer> endTimeList = chartResultPojo.getEndTimeList();
        FiscalYearTimePojo fiscalYearTimePojo = chartResultPojo.getFiscalYearTimePojo();
        boolean splitFlag = true;
        //处理每行数据
        for (int i = 0; i < dateTitleList.size(); i++) {
            TimePojo timePojo = throughHelp.formatThroughTimeInfo(splitFlag, fiscalYearTimePojo, startTimeList.get(i), endTimeList.get(i));
            String time = dateTitleList.get(i);
            String contractCount = contractCountList.get(i) + "";
            String contractAmount = ChartResultUtil.formatVal2Thousands(BigDecimal.valueOf(contractAmountList.get(i)), numFormatEnum);
            String paymentEd = ChartResultUtil.formatVal2Thousands(BigDecimal.valueOf(paymentEdList.get(i)), numFormatEnum);
            //表数据，是一个值一个对象
            ResultDataTableVO timeVO = new ResultDataTableVO(time, null);
            ThroughDTO throughDto = new ThroughDTO(chartResultPojo, SystemCodeEnum.CONTRACT_COUNT_CHART);
            ResultDataTableVO countVO = throughHelp.formatResultDataTableVO(contractCount, throughDto, timePojo);
            ThroughDTO throughDtoValid = new ThroughDTO(chartResultPojo, SystemCodeEnum.CONTRACT_AMOUNT_CHART);
            ResultDataTableVO amountVO = throughHelp.formatResultDataTableVO(contractAmount, throughDtoValid, timePojo);
            ThroughDTO throughDtoEd = new ThroughDTO(chartResultPojo, SystemCodeEnum.PAYMENT_ED_CHART);
            ResultDataTableVO paymentEdVo = throughHelp.formatResultDataTableVO(paymentEd, throughDtoEd, timePojo);
            List<ResultDataTableVO> resultDataTableVOs = Arrays.asList(timeVO, countVO, amountVO, paymentEdVo);
            resultDataTableVOList.add(resultDataTableVOs);
        }
        resultTableVO.setData(resultDataTableVOList);
        //-----表相关塞入最终结果chartResultDetailVO内
        chartResultDetailVO.setTable(resultTableVO);
        return chartResultDetailVO;
    }
    /**
     * 红冲合同总金额
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return java.lang.Object
     * @throws XbbException
     * @author zcp
     * @date 2019/3/1 15:28
     * @since v1.0
     * @version v1.0
     */
    public Object redContractChart(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        List<String> legendList = Arrays.asList(I18nMessageUtil.getMessage(ChartI18Constant.RED_FLUSH_CONTRACT_NUMBER_ANALYSIS).split(","));
        String unit = systemChartHelp.getUnit(I18nMessageUtil.getMessage(CommonConstant.YUAN));
        String unit1 = systemChartHelp.getUnit("%");
        List<String> unitList = Arrays.asList(unit, unit, unit, unit1, unit1);
        //获取红冲合同
        Integer isRed = 1;
        StatisticResultDTO statisticResultDto = getStatisticResultDto4MomYoy(isRed, false, chartResultPojo, legendList, unitList, ContractEnum.AMOUNT);

        //右侧展示总数
        statisticResultDto.setTotalFlag(true);
        statisticResultDto.setValueTitle(I18nMessageUtil.getMessage(ChartI18Constant.RED_FLUSH_CONTRACT_TOTAL_MONEY));
        chartResultDetailVO = systemChartHelp.packageResult(statisticResultDto, chartResultPojo, chartResultDetailVO);
        return chartResultDetailVO;
    }
    /**
     * 合同金额客户排名
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return java.lang.Object
     * @throws XbbException
     * @author zcp
     * @date 2019/2/28 23:19
     * @since v1.0
     * @version v1.0
     */
    public Object contractCustomerChartTop(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        chartResultPojo.setValueTypeEnum(ValueTypeEnum.VALUE_MONEY);
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.contractQuery4SignNoRed(chartResultPojo);
        String termsField = ContractEnum.getEsAttr4Keyword(ContractEnum.LINK_CUSTOMER);
        String sumField = ContractEnum.getEsAttr4Keyword(ContractEnum.AMOUNT);
        TopResultPojo topResultPojo = systemChartHelp.getTopResultPojo4CustomerTop(IndexTypeEnum.IDX_SAAS_CONTRACT, chartResultPojo.getCorpid(), boolQueryBuilder, termsField, sumField);

        String seriesName = I18nMessageUtil.getMessage(I18nStringConstant.CONTRACT_AMOUNT);
        return systemChartHelp.result4Top(chartResultPojo, chartResultDetailVO, topResultPojo, seriesName);
    }

    /**
     * 获取合同数量/金额的环比、同比
     *
     * @param countFlag           true处理合同数量，false处理合同金额
     * @param momFlag             true环比mom；false同比yoy
     * @param attrEnum            字段，如合同金额、合同毛利、现金毛利
     * @param chartResultPojo     入参，包含公司id，员工id、时间和部门筛选信息
     * @param chartResultDetailVO 出参
     * @return java.lang.Object
     * @throws XbbException 判断业绩分配时会抛出异常
     * @author 徐俊杰
     * @date 2019/3/2 11:29
     * @since v1.0
     */
    public Object contractMomYoy(boolean countFlag, boolean momFlag, ContractEnum attrEnum, ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        //数量环比
        ElasticAggsPojo elasticAggsPojo = getRateAggsPojo4MomYoy(chartResultPojo, countFlag, momFlag, attrEnum);
        ThroughDTO throughDTO = null;
        //是否画入表格内 0否1是
        Integer tableFlag = 0;
        String legend = null;
        String unit = null;
        Boolean totalFlag = false;
        String valueTitle = null;
        return systemChartHelp.packageResult4One(elasticAggsPojo, chartResultPojo, chartResultDetailVO, throughDTO, tableFlag, legend, unit, totalFlag, valueTitle);
    }

    /**
     * 红冲合同当月金额
     *
     * @param chartResultPojo 入参，包含公司id，员工id、时间和部门筛选信息
     * @param chartResultDetailVO 出参
     * @return java.lang.Object
     * @throws XbbException 判断业绩分配时会抛出异常
     * @author 徐俊杰
     * @date 2019/3/2 14:44
     * @since v1.0
     */
    public Object redContractHome(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        ElasticAggsPojo resultAggsPojo = getElasticAggsPojo(1, false, chartResultPojo, ContractEnum.AMOUNT);
        ThroughDTO throughDTO = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        //是否画入表格内 0否1是
        Integer tableFlag = 0;
        String legend = null;
        String unit = null;
        Boolean totalFlag = false;
        String valueTitle = null;
        return systemChartHelp.packageResult4One(resultAggsPojo, chartResultPojo, chartResultDetailVO, throughDTO, tableFlag, legend, unit, totalFlag, valueTitle);
    }

    /**
     * 合同毛利分析
     *
     * @param chartResultPojo     入参，包含公司id，员工id、时间和部门筛选信息
     * @param chartResultDetailVO 出参
     * @return java.lang.Object
     * @throws XbbException 判断业绩分配时会抛出异常
     * @author 徐俊杰
     * @date 2019/3/4 15:54
     * @since v1.0
     */
    public Object contractProfitChart(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        List<String> legendList = Arrays.asList(I18nMessageUtil.getMessage(ChartI18Constant.CONTRACT_PROFIT_CHART_CONTENT).split(","));
        String unit = systemChartHelp.getUnit(I18nMessageUtil.getMessage(CommonConstant.YUAN));
        String unit1 = systemChartHelp.getUnit("%");
        List<String> unitList = Arrays.asList(unit, unit, unit, unit1,unit1);
        StatisticResultDTO statisticResultDto = getStatisticResultDto4MomYoy(0,false, chartResultPojo, legendList, unitList, ContractEnum.GROSS_PROFIT);
        //右侧展示总数
        statisticResultDto.setTotalFlag(true);
        statisticResultDto.setValueTitle(I18nMessageUtil.getMessage(ChartI18Constant.TOTAL_CONTRACT_GROSS_PROFIT));
        chartResultDetailVO = systemChartHelp.packageResult(statisticResultDto, chartResultPojo, chartResultDetailVO);
        return chartResultDetailVO;
    }
    /**
     * 合同毛利总数
     * @param chartResultPojo
     * @return java.lang.String 
     * @throws XbbException
     * @author zcp
     * @date 2019/3/29 13:48
     * @since v1.0
     * @version v1.0
     */
    public String contractProfitBoard(ChartResultPojo chartResultPojo) throws XbbException {
        //不限制红冲合同
        Integer isRed = null;
        //ES获取合同金额
        ElasticAggsPojo elasticAggsPojo = contractAmount2ElasticAggsPojo(isRed, chartResultPojo, ValueTypeEnum.VALUE_TYPE, ContractEnum.GROSS_PROFIT);
        return ChartResultUtil.formatValue2String(false, ValueTypeEnum.VALUE_MONEY, false, elasticAggsPojo.getTotal(), NumFormatEnum.getByCode(chartResultPojo.getNumFormat()), chartResultPojo.getNumFormatFlag());
    }

    /**
     * 现金毛利分析
     *
     * @param chartResultPojo     入参，包含公司id，员工id、时间和部门筛选信息
     * @param chartResultDetailVO 出参
     * @return java.lang.Object
     * @throws XbbException 判断业绩分配时会抛出异常
     * @author 徐俊杰
     * @date 2019/3/4 16:07
     * @since v1.0
     */
    public Object contractProfitChartCash(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        List<String> legendList = Arrays.asList(I18nMessageUtil.getMessage(ChartI18Constant.CONTRACT_PROFIT_CASH_CHART_CONTENT).split(","));
        String unit = systemChartHelp.getUnit(I18nMessageUtil.getMessage(CommonConstant.YUAN));
        String unit1 = systemChartHelp.getUnit("%");
        List<String> unitList = Arrays.asList(unit, unit, unit, unit1,unit1);
        StatisticResultDTO statisticResultDto = getStatisticResultDto4MomYoy(0,false, chartResultPojo, legendList, unitList, ContractEnum.CASH_PROFIT);
        //右侧展示总数
        statisticResultDto.setTotalFlag(true);
        statisticResultDto.setValueTitle(I18nMessageUtil.getMessage(ChartI18Constant.GROSS_CASH_PROFIT));
        chartResultDetailVO = systemChartHelp.packageResult(statisticResultDto, chartResultPojo, chartResultDetailVO);
        return chartResultDetailVO;
    }

    /**
     * 签约合同数pk
     * @param userEntity 登录员工信息
     * @param chartResultPkPojo pk参数
     * @param chartResultPkDetailVO 塞入pk结果
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException
     * @author zcp
     * @date 2019/3/18 16:10
     * @since v1.0
     * @version v1.0
     */
    public ChartResultPkDetailVO pkContractCount(UserEntity userEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO) throws XbbException {
        /*--------处理查询条件：不限制签订人、不限制红冲--------*/
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.contractQuery4LimitStart(false, null, chartResultPkPojo);
        String fieldGroup = ContractEnum.getEsAttr4Keyword(ContractEnum.SIGN_PERSON);
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("aggs01").field(fieldGroup);
        termsAggregationBuilder.executionHint(ElasticConstant.EXECUTION_HINT);
        int pkType = chartResultPkPojo.getPkType();
        return pkHelp.getPkResult4Count(userEntity, chartResultPkPojo, chartResultPkDetailVO, IndexTypeEnum.IDX_SAAS_CONTRACT, boolQueryBuilder, termsAggregationBuilder, pkType);
    }

    /**
     * 签约合同数pk
     * @param userEntity 登录员工信息
     * @param chartResultPkPojo pk参数
     * @param chartResultPkDetailVO 塞入pk结果
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException
     * @author zcp
     * @date 2019/3/18 16:10
     * @since v1.0
     * @version v1.0
     */
    public ChartResultPkDetailVO pkRuleContractCount(UserEntity userEntity, ChartEntity chartEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO) throws XbbException {
        /*--------处理查询条件：不限制签订人、不限制红冲--------*/
        BoolQueryBuilder boolQueryBuilder = chartRuleQueryHelp.contractQuery4LimitStart(true, null, chartEntity, chartResultPkPojo);
        // chartRuleQueryHelp.formOpenBase(boolQueryBuilder, chartResultPkPojo, XbbRefTypeEnum.CONTRACT);
        String fieldGroup = ContractEnum.getEsAttr4Keyword(ContractEnum.SIGN_PERSON);
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("aggs01").field(fieldGroup);
        termsAggregationBuilder.executionHint(ElasticConstant.EXECUTION_HINT);
        int pkType = chartResultPkPojo.getPkType();
        return pkRuleHelp.getPkResult4Count(userEntity, chartEntity, chartResultPkPojo, chartResultPkDetailVO, IndexTypeEnum.IDX_SAAS_CONTRACT, boolQueryBuilder, termsAggregationBuilder, pkType);
    }

    /**
     * 合同金额pk
     * @param userEntity 登录员工
     * @param chartResultPkPojo pk参数
     * @param chartResultPkDetailVO 塞入pk结果
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException
     * @author zcp
     * @date 2019/3/20 20:28
     * @since v1.0
     * @version v1.0
     */
    public ChartResultPkDetailVO pkRuleContractAmount(UserEntity userEntity, ChartEntity chartEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO) throws XbbException {
        ContractEnum attrEnum = ContractEnum.AMOUNT;
        return pkRuleContract4Amount(userEntity, chartEntity, chartResultPkPojo, chartResultPkDetailVO, attrEnum);
    }

    /**
     * 合同毛利pk
     * @param userEntity 登录员工
     * @param chartResultPkPojo pk参数
     * @param chartResultPkDetailVO 塞入pk结果
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException
     * @author zcp
     * @date 2019/3/20 20:28
     * @since v1.0
     * @version v1.0
     */
    public ChartResultPkDetailVO pkRuleContractProfit(UserEntity userEntity, ChartEntity chartEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO) throws XbbException {
        ContractEnum attrEnum = ContractEnum.GROSS_PROFIT;
        return pkRuleContract4Amount(userEntity,chartEntity, chartResultPkPojo, chartResultPkDetailVO, attrEnum);
    }

    /**
     * 合同金额pk
     * @param userEntity 登录员工
     * @param chartResultPkPojo pk参数
     * @param chartResultPkDetailVO 塞入pk结果
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException
     * @author zcp
     * @date 2019/3/20 20:28
     * @since v1.0
     * @version v1.0
     */
    public ChartResultPkDetailVO pkContractAmount(UserEntity userEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO) throws XbbException {
        ContractEnum attrEnum = ContractEnum.AMOUNT;
        return pkContract4Amount(userEntity, chartResultPkPojo, chartResultPkDetailVO, attrEnum);
    }

    /**
     * 合同毛利pk
     * @param userEntity 登录员工
     * @param chartResultPkPojo pk参数
     * @param chartResultPkDetailVO 塞入pk结果
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException
     * @author zcp
     * @date 2019/3/20 20:28
     * @since v1.0
     * @version v1.0
     */
    public ChartResultPkDetailVO pkContractProfit(UserEntity userEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO) throws XbbException {
        ContractEnum attrEnum = ContractEnum.GROSS_PROFIT;
        return pkContract4Amount(userEntity, chartResultPkPojo, chartResultPkDetailVO, attrEnum);
    }


    //-------------------private方法-------------------
    /**
     * 获取合同数量的ElasticAggsPojo
     *
     * @param chartResultPojo 请求系统指标接口需要用到的pojo类
     * @param valueTypeEnum 值的类型
     * @return com.xbongbong.paas.elasticsearch.pojo.ElasticAggsPojo
     * @throws XbbException
     * @author 徐俊杰
     * @date 2019/2/28 9:20
     * @since v1.0
     */
    private ElasticAggsPojo contractCount2ElasticAggsPojo(ChartResultPojo chartResultPojo, ValueTypeEnum valueTypeEnum) throws XbbException {
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.contractQuery4SignNoRed(chartResultPojo);
        String fieldTime = ContractEnum.getEsAttr4Keyword(ContractEnum.SIGN_TIME);
        return systemChartHelp.getCount4Agg(chartResultPojo, valueTypeEnum, IndexTypeEnum.IDX_SAAS_CONTRACT, boolQueryBuilder, fieldTime);
    }

    /**
     * 获取合同金额pojo
     * @param isRed 是否红冲，null不作为筛选条件，1是0否
     * @param chartResultPojo
     * @param valueTypeEnum
     * @param attrEnum 字段，如合同金额、合同毛利、现金毛利
     * @return com.xbongbong.paas.elasticsearch.pojo.ElasticAggsPojo
     * @throws XbbException
     * @author zcp
     * @date 2019/2/28 13:57
     * @since v1.0
     * @version v1.0
     */
    private ElasticAggsPojo contractAmount2ElasticAggsPojo(Integer isRed, ChartResultPojo chartResultPojo, ValueTypeEnum valueTypeEnum, ContractEnum attrEnum) throws XbbException {
        String corpid = chartResultPojo.getCorpid();
        chartResultPojo.setValueTypeEnum(ValueTypeEnum.VALUE_MONEY);
        //合同业绩分配是否开启
        boolean openRule = companyConfigModel.hasBeenEnable(corpid, CompanyConfigEnum.CONTRACT_PERFORMANCE_RULE_SET.getAlias(),"1");
        if (openRule) {
            //非pk榜、限制分配人
            List<ContractPerformanceInfoVO> perforList = getContractPerformanceInfoVoList(isRed, chartResultPojo, true, attrEnum);
            //封装最后返回结果
            return systemChartHelp.getResult4OpenPerforRule(chartResultPojo, perforList);
        }else {
            String sumField = ContractEnum.getEsAttr4Keyword(attrEnum);
            BoolQueryBuilder boolQueryBuilder = chartQueryHelp.contractQuery4Sign(isRed, chartResultPojo);
            String fieldTime = ContractEnum.getEsAttr4Keyword(ContractEnum.SIGN_TIME);
            /*
             2019/4/6 不再按照多币种聚合求值 getAmount4Agg(chartResultPojo, valueTypeEnum, IndexTypeEnum.IDX_SAAS_CONTRACT, boolQueryBuilder, fieldTime, currencyField, sumField, currencyRateMap);
             */
            return systemChartHelp.getDouble4Agg(chartResultPojo, valueTypeEnum, IndexTypeEnum.IDX_SAAS_CONTRACT, boolQueryBuilder, fieldTime, sumField);
        }
    }

    /**
     * 合同金额类pk榜
     * @param userEntity 登录员工
     * @param chartResultPkPojo pk参数
     * @param chartResultPkDetailVO 塞入pk结果
     * @param attrEnum 合同字段
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException
     * @author zcp
     * @date 2019/3/20 20:24
     * @since v1.0
     * @version v1.0
     */
    private ChartResultPkDetailVO pkRuleContract4Amount(UserEntity userEntity, ChartEntity chartEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO, ContractEnum attrEnum) throws XbbException {
        String corpid = chartResultPkPojo.getCorpid();
        chartResultPkPojo.setValueTypeEnum(ValueTypeEnum.VALUE_MONEY);
        //合同业绩分配是否开启
        boolean openRule = companyConfigModel.hasBeenEnable(corpid, CompanyConfigEnum.CONTRACT_PERFORMANCE_RULE_SET.getAlias(),"1");
        if (openRule) {
            //pk榜、不限制分配人
            List<ContractPerformanceInfoVO> performanceInfoVoList = getRuleContractPerformanceInfoVoList(null, chartEntity, chartResultPkPojo, true, attrEnum);
            return pkRuleHelp.getPkResult4Performance(performanceInfoVoList, userEntity, chartEntity, chartResultPkPojo, chartResultPkDetailVO);
        }else {
            //塞入基础查询条件：不限制签订人、不限制红冲
            BoolQueryBuilder boolQueryBuilder = chartRuleQueryHelp.contractQuery4LimitStart(true, null, chartEntity, chartResultPkPojo);

            // chartRuleQueryHelp.formOpenBase(boolQueryBuilder, chartResultPkPojo, XbbRefTypeEnum.CONTRACT);

            String fieldGroup = ContractEnum.getEsAttr4Keyword(ContractEnum.SIGN_PERSON);
            String sumField = ContractEnum.getEsAttr4Keyword(attrEnum);
            int pkType = chartResultPkPojo.getPkType();
            IndexTypeEnum indexTypeEnum = IndexTypeEnum.IDX_SAAS_CONTRACT;
            return pkRuleHelp.getPkResult4Double(userEntity,chartEntity, chartResultPkPojo, chartResultPkDetailVO, indexTypeEnum, boolQueryBuilder, fieldGroup, sumField, pkType);
        }
    }

    /**
     * 合同金额类pk榜
     * @param userEntity 登录员工
     * @param chartResultPkPojo pk参数
     * @param chartResultPkDetailVO 塞入pk结果
     * @param attrEnum 合同字段
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException
     * @author zcp
     * @date 2019/3/20 20:24
     * @since v1.0
     * @version v1.0
     */
    private ChartResultPkDetailVO pkContract4Amount(UserEntity userEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO, ContractEnum attrEnum) throws XbbException {
        String corpid = chartResultPkPojo.getCorpid();
        chartResultPkPojo.setValueTypeEnum(ValueTypeEnum.VALUE_MONEY);
        //合同业绩分配是否开启
        boolean openRule = companyConfigModel.hasBeenEnable(corpid, CompanyConfigEnum.CONTRACT_PERFORMANCE_RULE_SET.getAlias(),"1");
        if (openRule) {
            //pk榜、不限制分配人
            List<ContractPerformanceInfoVO> performanceInfoVoList = getContractPerformanceInfoVoList(null, chartResultPkPojo, false, attrEnum);
            return pkHelp.getPkResult4Performance(performanceInfoVoList, userEntity, chartResultPkPojo, chartResultPkDetailVO);
        }else {
            //塞入基础查询条件：不限制签订人、不限制红冲
            BoolQueryBuilder boolQueryBuilder = chartQueryHelp.contractQuery4LimitStart(false, null, chartResultPkPojo);

            String fieldGroup = ContractEnum.getEsAttr4Keyword(ContractEnum.SIGN_PERSON);
            String sumField = ContractEnum.getEsAttr4Keyword(attrEnum);
            int pkType = chartResultPkPojo.getPkType();
            IndexTypeEnum indexTypeEnum = IndexTypeEnum.IDX_SAAS_CONTRACT;
            return pkHelp.getPkResult4Double(userEntity, chartResultPkPojo, chartResultPkDetailVO, indexTypeEnum, boolQueryBuilder, fieldGroup, sumField, pkType);
        }
    }
    /**
     * 签约合同数：该方法获取出总数、和各个桶内数值list，不会封装成图表需要的数据格式
     * @param chartResultPojo
     * @param valueTypeEnum
     * @return com.xbongbong.pro.statistic.pojo.vo.ResultCountListVO
     * @throws XbbException
     * @author zcp
     * @date 2019/2/28 19:47
     * @since v1.0
     * @version v1.0
     */
    private ResultCountListVO contractCount2ResultCountListVO(ChartResultPojo chartResultPojo, ValueTypeEnum valueTypeEnum) throws XbbException {
        ElasticAggsPojo elasticAggsPojo = contractCount2ElasticAggsPojo(chartResultPojo, valueTypeEnum);
        return systemChartHelp.getResultCountListVO(elasticAggsPojo);
    }
    /**
     * 签约合同金额：该方法获取出总值、和各个桶内数值list，不会封装成图表需要的数据格式
     * @param chartResultPojo
     * @param valueTypeEnum
     * @return com.xbongbong.pro.statistic.pojo.vo.ResultDoubleListVO
     * @throws XbbException
     * @author zcp
     * @date 2019/2/28 19:49
     * @since v1.0
     * @version v1.0
     */
    private ResultDoubleListVO contractAmount2ResultDoubleListVO(ChartResultPojo chartResultPojo, ValueTypeEnum valueTypeEnum) throws XbbException {
        Integer isRed = null;
        ElasticAggsPojo elasticAggsPojo = contractAmount2ElasticAggsPojo(isRed, chartResultPojo, valueTypeEnum, ContractEnum.AMOUNT);
        return systemChartHelp.getResultDoubleListVO(elasticAggsPojo);
    }
    /**
     * 获取并封装环比、同比统计结果，默认不限制是否红冲
     * @param countFlag true处理合同数量，false处理合同金额
     * @param chartResultPojo 参数pojo
     * @param legendList 图的legend
     * @param unitList 各条线的单位，与legendList大小一致
     * @param attrEnum 字段，如合同金额、合同毛利、现金毛利
     * @return com.xbongbong.pro.statistic.pojo.dto.StatisticResultDTO
     * @throws XbbException
     * @author zcp
     * @date 2019/2/28 14:39
     * @since v1.0
     * @version v1.0
     */
    private StatisticResultDTO getStatisticResultDto4MomYoy(boolean countFlag, ChartResultPojo chartResultPojo, List<String> legendList, List<String> unitList, ContractEnum attrEnum) throws XbbException {
        //默认不限制是否红冲
        return  getStatisticResultDto4MomYoy(null, countFlag, chartResultPojo, legendList, unitList, attrEnum);
    }
    /**
     * 同时获取并封装环比、同比统计结果，是否红冲，通过isRed限制
     * @param isRed 是否红冲，null不作为筛选条件，1是0否
     * @param countFlag true处理合同数量，false处理合同金额
     * @param chartResultPojo 参数pojo
     * @param legendList 图的legend
     * @param unitList 各条线的单位，与legendList大小一致
     * @param attrEnum 字段，如合同金额、合同毛利、现金毛利
     * @return com.xbongbong.pro.statistic.pojo.dto.StatisticResultDTO
     * @throws XbbException
     * @author zcp
     * @date 2019/3/1 15:27
     * @since v1.0
     * @version v1.0
     */
    private StatisticResultDTO getStatisticResultDto4MomYoy(Integer isRed, boolean countFlag, ChartResultPojo chartResultPojo, List<String> legendList, List<String> unitList, ContractEnum attrEnum) throws XbbException {
        //------当前筛选时间的结果
        ElasticAggsPojo thisMonthAggsPojo = getElasticAggsPojo(isRed, countFlag, chartResultPojo, attrEnum);
        //先把chartResultPojo拷贝出一份，下面都用chartResultPojoCopy，防止时间的变更（环比、同比需要改变开始结束时间）对原有chartResultPojo内参数的影响
        ChartResultPojo chartResultPojoCopy = new ChartResultPojo();
        BeanUtil.copyProperties(chartResultPojo, chartResultPojoCopy);
        Integer startTime = chartResultPojo.getStartTime();
        Integer endTime = chartResultPojo.getEndTime();
        //获取环比同比各自的时间列表
        List<Integer> startTimeList = chartResultPojoCopy.getStartTimeList();
        MomYoyTimeListPojo momYoyTimeListPojo = ChartResultUtil.momYoyTimeListPojo(startTimeList);
        //环比时间处理
        ChartResultUtil.momOrYoyTime(chartResultPojoCopy, true, startTime, endTime);
        chartResultPojoCopy.setStartTimeList(momYoyTimeListPojo.getMomTimeListPojo().getStartTimeList());
        chartResultPojoCopy.setEndTimeList(momYoyTimeListPojo.getMomTimeListPojo().getEndTimeList());
        //------环比结果
        ElasticAggsPojo lastMonthAggsPojo = getElasticAggsPojo(isRed, countFlag, chartResultPojoCopy, attrEnum);
        //同比时间处理
        ChartResultUtil.momOrYoyTime(chartResultPojoCopy, false, startTime, endTime);
        chartResultPojoCopy.setStartTimeList(momYoyTimeListPojo.getYoyTimeListPojo().getStartTimeList());
        chartResultPojoCopy.setEndTimeList(momYoyTimeListPojo.getYoyTimeListPojo().getEndTimeList());
        //------同比结果
        ElasticAggsPojo lastYearAggsPojo = getElasticAggsPojo(isRed, countFlag, chartResultPojoCopy, attrEnum);
        //------处理环比、同比比例
        ElasticAggsPojo resultMom = systemChartHelp.getMomYoyResult(thisMonthAggsPojo, lastMonthAggsPojo);
        ElasticAggsPojo resultYoy = systemChartHelp.getMomYoyResult(thisMonthAggsPojo, lastYearAggsPojo);

        List<StatisticResultInfoDTO> statisticResultInfoDtoList = systemChartHelp.getInfoDtos4MomYoy(chartResultPojo, legendList, unitList, thisMonthAggsPojo, lastMonthAggsPojo, lastYearAggsPojo, resultMom, resultYoy);
        StatisticResultDTO statisticResultDto = new StatisticResultDTO(true, thisMonthAggsPojo.getTotal(), null, statisticResultInfoDtoList);
        return statisticResultDto;
    }

    /**
     * 获取环比比例或者同比比例（不是同时获取）
     *
     * @param chartResultPojo 入参，包含公司id，员工id、时间和部门筛选信息
     * @param countFlag       true处理合同数量，false处理合同金额
     * @param momFlag         true环比mom；false同比yoy
     * @param attrEnum        字段，如合同金额、合同毛利、现金毛利
     * @return com.xbongbong.paas.elasticsearch.pojo.ElasticAggsPojo
     * @throws XbbException 判断业绩分配时会抛出异常
     * @author 徐俊杰
     * @date 2019/3/2 11:27
     * @since v1.0
     */
    private ElasticAggsPojo getRateAggsPojo4MomYoy(ChartResultPojo chartResultPojo, boolean countFlag, boolean momFlag, ContractEnum attrEnum) throws XbbException {
        Integer startTime = chartResultPojo.getStartTime();
        Integer endTime = chartResultPojo.getEndTime();
        //------当前筛选时间的结果
        ElasticAggsPojo thisMonthAggsPojo = getElasticAggsPojo(null, countFlag, chartResultPojo, attrEnum);
        //------环比、同比结果
        //先把chartResultPojo拷贝出一份，下面都用chartResultPojoCopy，防止时间的变更（环比、同比需要改变开始结束时间）对原有chartResultPojo内参数的影响
        ChartResultPojo chartResultPojoCopy = new ChartResultPojo();
        BeanUtil.copyProperties(chartResultPojo, chartResultPojoCopy);
        ChartResultUtil.momOrYoyTime(chartResultPojoCopy, momFlag, startTime, endTime);
        ElasticAggsPojo lastMonthAggsPojo = getElasticAggsPojo(null, countFlag, chartResultPojoCopy, attrEnum);
        //------处理环比比例
        return systemChartHelp.getMomYoyResult(thisMonthAggsPojo, lastMonthAggsPojo);
    }

    /**
     * 获取合同统计结果
     * @param isRed 是否红冲，null不作为筛选条件，1是0否
     * @param countFlag true处理合同数量，false处理合同金额
     * @param chartResultPojo 参数pojo
     * @param attrEnum 字段，如合同金额、合同毛利、现金毛利
     * @return com.xbongbong.paas.elasticsearch.pojo.ElasticAggsPojo
     * @author zcp
     * @date 2019/2/28 14:42
     * @since v1.0
     * @version v1.0
     */
    private ElasticAggsPojo getElasticAggsPojo(Integer isRed, boolean countFlag, ChartResultPojo chartResultPojo, ContractEnum attrEnum) throws XbbException {
        ElasticAggsPojo elasticAggsPojo;
        if (countFlag) {
            elasticAggsPojo = contractCount2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.ARRAY_TYPE);
        } else {
            elasticAggsPojo = contractAmount2ElasticAggsPojo(isRed, chartResultPojo, ValueTypeEnum.ARRAY_TYPE, attrEnum);
        }
        return elasticAggsPojo;
    }
    /**
     * 获取业绩分配list
     * 开启业绩分配，则先查业绩分配es（限制分配人<根据userFlag判断是否限制组织架构>、合同签订时间范围），然后再查tb_saas_contract表，得到合同金额、毛利等相关信息
     * @param isRed 是否红冲，null不作为筛选条件，1是0否
     * @param chartResultBasePojo 统计参数pojo
     * @param userFlag 是否在查询时限制分配人list
     * @param attrEnum 字段，如合同金额、合同毛利、现金毛利
     * @return java.util.List<com.xbongbong.pro.statistic.pojo.vo.ContractPerformanceInfoVO>
     * @throws XbbException
     * @author zcp
     * @date 2019/3/20 19:59
     * @since v1.0
     * @version v1.0
     */
    private List<ContractPerformanceInfoVO> getContractPerformanceInfoVoList(Integer isRed, ChartResultBasePojo chartResultBasePojo, boolean userFlag, ContractEnum attrEnum) throws XbbException {
        //-------------业绩分配：组织架构（合同的签订时间作为父条件限制）
        BoolQueryBuilder performanceQueryBuilder = chartQueryHelp.contractQuery4performance2Child(isRed, userFlag, chartResultBasePojo);
        //-------------（1）先查业绩分配es（限制分配人<根据userFlag判断是否限制组织架构>、合同签订时间范围）
        List<ContractPerformanceEntity> performanceList = formHelp.getContractPerformanceList(chartResultBasePojo.getCorpid(), performanceQueryBuilder);
        //-------------（2）然后把contractId作为条件再查合同，并且得到合同id--合同相关信息Object的对应关系map
        Map<Long, ContractInfoVO> cidContractMap = findContract(performanceList, chartResultBasePojo, attrEnum);
        //-------------（3）封装结果
        return formatPerformanceInfoVoList(performanceList, cidContractMap);
    }

    /**
     * 获取业绩分配list
     * 开启业绩分配，则先查业绩分配es（限制分配人<根据userFlag判断是否限制组织架构>、合同签订时间范围），然后再查tb_saas_contract表，得到合同金额、毛利等相关信息
     * @param isRed 是否红冲，null不作为筛选条件，1是0否
     * @param chartResultBasePojo 统计参数pojo
     * @param userFlag 是否在查询时限制分配人list
     * @param attrEnum 字段，如合同金额、合同毛利、现金毛利
     * @return java.util.List<com.xbongbong.pro.statistic.pojo.vo.ContractPerformanceInfoVO>
     * @throws XbbException
     * @author zcp
     * @date 2019/3/20 19:59
     * @since v1.0
     * @version v1.0
     */
    private List<ContractPerformanceInfoVO> getRuleContractPerformanceInfoVoList(Integer isRed, ChartEntity chartEntity, ChartResultBasePojo chartResultBasePojo, boolean userFlag, ContractEnum attrEnum) throws XbbException {
        //-------------业绩分配：组织架构（合同的签订时间作为父条件限制）
        BoolQueryBuilder performanceQueryBuilder = chartRuleQueryHelp.contractQuery4performance2Child(isRed, chartEntity, userFlag, chartResultBasePojo);
        //-------------（1）先查业绩分配es（限制分配人<根据userFlag判断是否限制组织架构>、合同签订时间范围）
        List<ContractPerformanceEntity> performanceList = formHelp.getContractPerformanceList(chartResultBasePojo.getCorpid(), performanceQueryBuilder);
        //-------------（2）然后把contractId作为条件再查合同，并且得到合同id--合同相关信息Object的对应关系map
        Map<Long, ContractInfoVO> cidContractMap = findContract(performanceList, chartResultBasePojo, attrEnum);
        //-------------（3）封装结果
        return formatPerformanceInfoVoList(performanceList, cidContractMap);
    }

    /**
     * （1）先根据业绩分配人、签订时间范围，查业绩分配es，得到一定时间范围的业绩分配数据
     * （2）从业绩分配list得到条件内的contractId查询合同表，从而得到amount（或毛利等）、signTime、currency，存入map（为处理最终结果提供数据）
     * （3）根据第一步的list和第2步的map信息，处理业绩分配
     * @param performanceList 符合条件的业绩分配list
     * @param chartResultBasePojo 参数
     * @param attrEnum 字段，如合同金额、合同毛利、现金毛利
     * @return java.util.Map<java.lang.Long,com.xbongbong.pro.statistic.pojo.vo.ContractInfoVO>
     * @throws XbbException
     * @author zcp
     * @date 2019/3/6 16:28
     * @since v1.0
     * @version v1.0
     */
    private Map<Long, ContractInfoVO> findContract(List<ContractPerformanceEntity> performanceList, ChartResultBasePojo chartResultBasePojo, ContractEnum attrEnum) throws XbbException {
        //根据业绩分配得到合同id
        Set<Long> contractIdIn = formHelp.getContractIdsFromPerformance(performanceList);
        ContractEnum enumAmount = ContractEnum.AMOUNT;
        ContractEnum enumSignTime = ContractEnum.SIGN_TIME;
        ContractEnum enumGrossProfit = ContractEnum.GROSS_PROFIT;
        ContractEnum enumCashProfit = ContractEnum.CASH_PROFIT;
        List<String> fieldList = Arrays.asList("id", ContractEnum.getAttrConnectData(enumAmount), ContractEnum.getAttrConnectData(enumSignTime), ContractEnum.getAttrConnectData(enumGrossProfit), ContractEnum.getAttrConnectData(enumCashProfit));
        //只读取出必要的字段
        String amountAttr = enumAmount.getAttr();
        String signTimeAttr = enumSignTime.getAttr();
        String currencyAttr = ContractEnum.CURRENCY.getAttr();
        String grossProfitAttr = enumGrossProfit.getAttr();
        String cashProfitAttr = enumCashProfit.getAttr();
        //模拟分页
        List<Long> contractIdInList = new ArrayList<>(contractIdIn);
        //合同id--合同相关信息实体
        Map<Long, ContractInfoVO> cidContractMap = new HashMap<>(contractIdInList.size());
        for (int i = 0; i < contractIdInList.size(); i+=PaasConstant.ES_MAX_PAGE_SIZE) {
            int toIndex = i +  PaasConstant.ES_MAX_PAGE_SIZE;
            if(toIndex > contractIdInList.size() ){
                toIndex = contractIdInList.size() ;
            }
            List<Long> newList = contractIdInList.subList(i, toIndex);
            if(CollectionsUtil.isNotEmpty(newList)){
                List<PaasFormDataEntityExt> list = formHelp.getFormListByIds4All(chartResultBasePojo.getCorpid(), IndexTypeEnum.IDX_SAAS_CONTRACT, newList, fieldList);
                for (PaasFormDataEntityExt entityExt : list) {
                    JSONObject data = entityExt.getData();
                    if (data == null) {
                        continue;
                    }
                    Long contractId = entityExt.getId();
                    ContractInfoVO contractInfoVO = new ContractInfoVO();
                    contractInfoVO.setId(contractId);
                    contractInfoVO.setTime(data.getInteger(signTimeAttr));
                    contractInfoVO.setCurrency(data.getLong(currencyAttr));
                    switch (attrEnum) {
                        case GROSS_PROFIT:
                            contractInfoVO.setAmount(data.getDoubleValue(grossProfitAttr));
                            break;
                        case CASH_PROFIT:
                            contractInfoVO.setAmount(data.getDoubleValue(cashProfitAttr));
                            break;
                        default:
                            contractInfoVO.setAmount(data.getDoubleValue(amountAttr));
                            break;
                    }
                    cidContractMap.put(contractId, contractInfoVO);
                }
            }
        }
        return cidContractMap;
    }
    /**
     * 封装数据
     * 注：金额币种已经转换好
     * @param performanceList 符合条件的业绩分配list
     * @param cidContractMap 合同id--合同相关信息实体
     * @return java.util.List<com.xbongbong.pro.statistic.pojo.vo.ContractPerformanceInfoVO>
     * @throws XbbException
     * @author zcp
     * @date 2019/3/6 19:46
     * @since v1.0
     * @version v1.0
     */
    private List<ContractPerformanceInfoVO> formatPerformanceInfoVoList(List<ContractPerformanceEntity> performanceList, Map<Long, ContractInfoVO> cidContractMap) {
        List<ContractPerformanceInfoVO> performanceInfoVoList = new ArrayList<>();
        //2019/4/6 不再按照多币种求值
        for (ContractPerformanceEntity entity : performanceList) {
            String userId = entity.getUserId();
            Long contractId = entity.getContractId();
            //该rate在表内储存时是做了乘以100处理的
            Double rate = entity.getRate();

            //业绩分配是基于contract查询出来，因此，业绩分配内contractId肯定在cidContractMap内有对应实体
            ContractInfoVO contractInfoVO = cidContractMap.get(contractId);
            Integer signTime = contractInfoVO.getTime();
            Double amount = contractInfoVO.getAmount();
            if (amount == null) {
                amount = 0D;
            } else {
                //-------先处理分配人所占比例
                amount = Arith.mul(amount, rate);
                amount = Arith.div(amount, 100, 2);
            }

            //-------再处理币种：将具体使用某种货币结算的金额转换成本币
            //汇率：按照币种汇率转为人民币amount=BasicHelper.getAmountByExchangeRate;
            ContractPerformanceInfoVO contractPerformanceInfoVO = new ContractPerformanceInfoVO();
            contractPerformanceInfoVO.setUserId(userId);
            contractPerformanceInfoVO.setTime(signTime);
            contractPerformanceInfoVO.setAmount(amount);
            performanceInfoVoList.add(contractPerformanceInfoVO);
        }
        return performanceInfoVoList;
    }
}
